const sRoot = __dirname;
const osFs = require('fs');
const osPath = require('path');
const { fsExistsSync, absolutePath, isFile } = require('../utils/fs');
const oGlobby = require('globby');

const reWhiteSpace = /[\s,]+/; // 逗号隔开

class BaseFinder {
  constructor(oOpts = {}) {
    this.oBaseOptions = {
      // 初始化参数
      ...oOpts,
    };
    this.oCheckOptions = {}; // check重设的参数，优先级高
    this.aPathPatterns = []; // 扫描白名单规则
    this.sRootPath; // 根目录
    this.sReportPath; // 输出的报告目录
    this.aFileList = []; // 扫描出来的文档

    this.oOraInstance;
  }

  fnCheck(saPatterns = null, oOpts = {}) {
    console.log("开始扫描");
    console.log("================");
    
    if (Array.isArray(saPatterns)) {
      this.aPathPatterns = saPatterns;
    } else {
      this.aPathPatterns.push(saPatterns);
    }

    this.aPathPatterns = this.aPathPatterns.map((sItem) => {
      return absolutePath(sItem);
    });

    this.oCheckOptions = {
      ...this.oBaseOptions,
      ...oOpts,
    };
    // 设定扫描项目根路径
    this.sRootPath = this.fnGetRootPath();

    // 设定输出路径
    this.fnSetReportPath();

    this.sReportPath = this.fnSetReportPath();

    if (this.aPathPatterns.length === 1 && isFile(this.aPathPatterns[0])) {
      this.aFileList = this.aPathPatterns;
    } else {
      // 设置根目录
      this.aFileList = this.fnGetFileList();
    }
    // console.log("baseFunish", this.aFileList)
  }

  // 设置输出结果路径
  fnSetReportPath() {
    const { sDirName, sOutput } = this.oCheckOptions;
    // 指定输出结果路径
    const sBasePath = !!sOutput ? absolutePath(sOutput) : this.sRootPath;
    return osPath.resolve(osPath.join(sBasePath, sDirName));
  }

  /**
   * 取根目录
   * retrun {string} sRootPath
   */
  fnGetRootPath() {
    if (this.aPathPatterns.length === 1) {
      const sPath = this.aPathPatterns[0];
      if (isFile(sPath)) {
        // 如果是文件，返回上一级
        return osPath.join(sPath, '../');
      }
      return sPath;
    } else {
      const aPath = this.aPathPatterns;
      let oMapPath = {};
      aPath.map((item) => {
        oMapPath[aPath.length] = item;
      });
      const aKeys = Object.getOwnPropertyNames(oMapPath);
      return osPath.join(oMapPath[aKeys[0]], '../');
    }
  }

  /**
   * 取符合的文件列表
   * return {array}
   */
  fnGetFileList() {
    const { sExt, sIgnorePath, sIgnorePattern } = this.oCheckOptions;

    let aIgnorePatternLst = []; // 格式 [ '.gitignore', '.eslintignore', '**/node_modules/*' ]

    // 过滤忽略路径
    if (sIgnorePath) {
      const aIgnorePathList = sIgnorePath.split(reWhiteSpace);
      aIgnorePathList.forEach((sItem) => {
        const sFullPath = osPath.join(this.sRootPath, sItem);
        // console.log('>>>: fnGetFileList -> sFullPath', sFullPath)
        if (fsExistsSync(sFullPath)) {
          const aCurrentIgnorePattern = osFs
            .readFileSync(absolutePath(sFullPath), 'utf-8')
            .split(reWhiteSpace);
          aIgnorePatternLst = aIgnorePathList.concat(aCurrentIgnorePattern);
        }
      });
      // 过滤数据
      aIgnorePatternLst = aIgnorePatternLst
        .filter((sItem) => {
          return !!sItem;
        })
        .map((sItem) => {
          return sItem.indexOf('*') > -1 ? `**/${sItem}` : sItem;
        });
    }
    // 过滤忽略规则
    if (sIgnorePattern) {
      const aCurrentIgnorePattern = sIgnorePattern.split(reWhiteSpace);
      aIgnorePatternLst = aIgnorePatternLst.concat(aCurrentIgnorePattern);
    }
    // console.log('>>>: fnGetFileList -> aIgnorePatternLst', aIgnorePatternLst);

    const oGlobbyOptions = {
      nodir: true,
      pw: this.sRootPath,
    };
    if (aIgnorePatternLst.length > 0) {
      oGlobbyOptions.ignore = aIgnorePatternLst;
    }
    // 处理文件格式
    const aExtList = sExt.split(reWhiteSpace);

    // console.log('>>>: this.aPathPatterns', this.aPathPatterns);
    /**
     * 遍历数组内容, 取得新的目录规则
     * ["~/xxx/src", "~/xxx/public"]
     * @param  {array} aPathPatterns
     * return  {array}
     */
    let aGlobbyPatterns = [];
    this.aPathPatterns.map((sPattern) => {
      try {
        if (osFs.lstatSync(sPattern).isDirectory()) {
          let aLst = aExtList.map((sExt) => {
            return sPattern + '/**/*' + sExt;
          });
          aGlobbyPatterns = [...aGlobbyPatterns, ...aLst];
        }
      } catch (e) {
        // console.log('>>>: fnGetFileList -> e', e, e.code);
        if (e.code === 'ENOENT') {
          // 可能是直接文件，所以有失败直接加回文件
          aGlobbyPatterns = [...aGlobbyPatterns, sPattern];
        } else {
          throw e;
        }
      }
    });
    // console.log("oGlobbyOptions", JSON.stringify(oGlobbyOptions, null,2))
    return oGlobby.sync(aGlobbyPatterns, oGlobbyOptions);
  }
}

module.exports = BaseFinder;
